package com.wifiscanner;

import java.util.List;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.wifiscanner.DBAdapter;


public class WiFiScannerActivity extends Activity {
	
	private static final int TWO_MINUTES = 1000 * 60 * 2;
	
	public static final int GPS_MIN_WAIT = 3000;
	public static final float GPS_MIN_METERS = 0;
	public static final int WIFI_MIN_WAIT = 500;
	public static final float WIFI_MIN_METERS = 1000;
	
	TextView mainText;
	TextView lonText;
	TextView latText;
	TextView altText;
	WifiManager wifiManager;
	LocationManager locManager;
	WifiReceiver receiverWifi;
	LocationTracker fineTracker;
	LocationTracker coarseTracker;
	Location lastLocation;
	
	SharedPreferences preferences;
	
	DBAdapter db;
	
	  /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        preferences = PreferenceManager.getDefaultSharedPreferences(this);
        String x = preferences.toString();
        
        Log.d("AHA", x);
        
        Button listButton = (Button) findViewById(R.id.listButton);
        Button mapButton = (Button) findViewById(R.id.mapButton);
        Button settingsButton = (Button) findViewById(R.id.settingsButton);  
        
        
        listButton.setOnClickListener(new Button.OnClickListener() 
        {
        	public void onClick(View v)
        	{
        		handleListButtonClick();
        	}
        });
        
      
        mapButton.setOnClickListener(new Button.OnClickListener() 
        {
        	public void onClick(View v)
        	{
        		handleMapButtonClick();
        	}
        });
      
        settingsButton.setOnClickListener(new Button.OnClickListener() 
        {
        	public void onClick(View v)
        	{
        		handleSettingsButtonClick();
        	}
        });
     
        db = new DBAdapter(this);
	    db.open();
            
	    mainText = (TextView) findViewById(R.id.mainText);
	    latText = (TextView) findViewById(R.id.latText);
	    lonText = (TextView) findViewById(R.id.lonText);
	    altText = (TextView) findViewById(R.id.altText);
	    
        wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
        locManager = (LocationManager) getSystemService(LOCATION_SERVICE);
        
        mainText.setMovementMethod(ScrollingMovementMethod.getInstance()); 
        
        receiverWifi = new WifiReceiver();   
        fineTracker = new LocationTracker();
        coarseTracker = new LocationTracker();
        
        registerTrackers();
        
        wifiManager.startScan();
        
        mainText.setText("\nWaiting for Wifi receiver\n");
        Log.d("WiFiScannerActivity", "Started");
    }
    
    // from google android dev guide
    private boolean isBetterLocation(Location location, Location currentBestLocation) 
    {
        if (currentBestLocation == null) {
            // A new location is always better than no location
            return true;
        }

        // Check whether the new location fix is newer or older
        long timeDelta = location.getTime() - currentBestLocation.getTime();
        boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
        boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
        boolean isNewer = timeDelta > 0;

        // If it's been more than two minutes since the current location, use the new location
        // because the user has likely moved
        if (isSignificantlyNewer) {
            return true;
        // If the new location is more than two minutes older, it must be worse
        } else if (isSignificantlyOlder) {
            return false;
        }

        // Check whether the new location fix is more or less accurate
        int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
        boolean isLessAccurate = accuracyDelta > 0;
        boolean isMoreAccurate = accuracyDelta < 0;
        boolean isSignificantlyLessAccurate = accuracyDelta > 200;

        // Check if the old and new location are from the same provider
        boolean isFromSameProvider = isSameProvider(location.getProvider(),
                currentBestLocation.getProvider());

        // Determine location quality using a combination of timeliness and accuracy
        if (isMoreAccurate) {
            return true;
        } else if (isNewer && !isLessAccurate) {
            return true;
        } else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
            return true;
        }
        return false;
    }

    /** Checks whether two providers are the same */
    private boolean isSameProvider(String provider1, String provider2) {
        if (provider1 == null) {
          return provider2 == null;
        }
        return provider1.equals(provider2);
    }
    
    public void setLocation(Location location) 
    {
    	if (location != null  && isBetterLocation(location, lastLocation)) {
    		// record it for db update
    		lastLocation = location;
    		// update screen
    		Double lat = lastLocation.getLatitude();
			Double lon = lastLocation.getLongitude();
			Double alt = lastLocation.getAltitude();

		    latText.setText(String.format("%.4f", lat));
		    lonText.setText(String.format("%.4f", lon));
		    altText.setText(String.format("%.4f", alt));
    	}
    }
    
    private void registerTrackers() 
    {
    	
    	Criteria fine = new Criteria();
    	fine.setAccuracy(Criteria.ACCURACY_FINE);
    	Criteria coarse = new Criteria();
    	coarse.setAccuracy(Criteria.ACCURACY_COARSE);
    	
    	String fineProvider = locManager.getBestProvider(fine, true);
    	String coarseProvider = locManager.getBestProvider(coarse, true);
    	
    	Location fineLocation = locManager.getLastKnownLocation(fineProvider);
        Location coarseLocation = locManager.getLastKnownLocation(coarseProvider);
    
        setLocation(coarseLocation);
    	setLocation(fineLocation);
    	
    	String x1 = preferences.getString("gps_min_time", "3000");
    	String x2 = preferences.getString("gps_min_dist", "0");
    	String x3 = preferences.getString("wifi_min_time", "500");
    	String x4 = preferences.getString("wifi_min_dist", "1000");
    	
    	Log.d("aha", x1);
    	Log.d("aha", x2);
    	Log.d("aha", x3);
    	Log.d("aha", x4);
    	
    	long gps_min_time = Long.parseLong(x1); 
    	float gps_min_dist = Float.parseFloat(x2);
        long wifi_min_time = Long.parseLong(x3);
        float wifi_min_dist = Float.parseFloat(x4);

    	
    	//long gps_min_wait = preferences.getLong("gps_min_time", GPS_MIN_WAIT);
    	//long gps_min_wait = preferences.getLong("gps_min_time", GPS_MIN_WAIT);
        //float gps_min_dist = preferences.getFloat("gps_min_dist", GPS_MIN_METERS);
        //long wifi_min_wait = preferences.getLong("wifi_min_time", WIFI_MIN_WAIT);
        //float wifi_min_dist = preferences.getFloat("wifi_min_dist", WIFI_MIN_METERS);
        
    	locManager.requestLocationUpdates(coarseProvider, wifi_min_time, wifi_min_dist, coarseTracker);
    	locManager.requestLocationUpdates(fineProvider, gps_min_time, gps_min_dist, fineTracker);
    	registerReceiver(receiverWifi, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
        
    }
    
	protected void onDestroy() 
	{
		db.close();
	    super.onDestroy();
	}


	protected void onPause() 
	{
		unregisterReceiver(receiverWifi);
		locManager.removeUpdates(coarseTracker);
		locManager.removeUpdates(fineTracker);
		super.onPause();
	}

	protected void onResume() 
	{
		registerTrackers();
    	super.onResume();
	}
	
    private void handleListButtonClick()
    {
    	Intent intent = new Intent(WiFiScannerActivity.this, ListViewActivity.class);
   		startActivity(intent);	
    }
  
    private void handleMapButtonClick()
    {
    	Intent intent = new Intent(WiFiScannerActivity.this, MapViewActivity.class);
   		startActivity(intent);	
    }
    
    private void handleSettingsButtonClick()
    {
		Intent settingsActivity = new Intent(getBaseContext(),SettingsActivity.class);
		startActivity(settingsActivity);
    }

    
	public boolean onCreateOptionsMenu(Menu menu) {
		menu.add(0, 0, 0, "Refresh");
		return super.onCreateOptionsMenu(menu);
	}

	public boolean onMenuItemSelected(int featureId, MenuItem item) {
		wifiManager.startScan();
		mainText.setText("Starting Scan");
		return super.onMenuItemSelected(featureId, item);
	}
	
	private void updateDB(ScanResult result, double lat, double lon, double alt)
	{			
			AccessPoint point = db.getAccessPoint(result.BSSID);
			if (point == null) {
				point = new AccessPoint();
				point.setScanResult(result);
				point.lat = lat;
				point.lon = lon;
				point.alt = alt;
				db.setAccessPoint(point);
			}
			else {
				int update = 0;
				if (!point.SSID.equals(result.SSID)
						|| !point.capabilities.equals(result.capabilities) 
						|| point.frequency != result.frequency) 
				{
					point.SSID = result.SSID;
					point.capabilities = result.capabilities;
					point.frequency = result.frequency;
					update++;
				}
				
				// always update with a location fix if none previously set
				if (point.isZeroFix()) {
					point.lat = lat;
					point.lon = lon;
					point.alt = alt;
					update++;
				}

				if (result.level > point.level) {
					point.level = result.level;
					// update location only if set
					if (!AccessPoint.isZeroFix(lat, lon, alt)) {
						point.lat = lat;
						point.lon = lon;
						point.alt = alt;
					}
					update++;
				}
				if (update > 0) {
					point.timestamp =System.currentTimeMillis();
					db.setAccessPoint(point);
				}
			}
	}
	
	private class LocationTracker implements LocationListener {
		

		@Override
		public void onLocationChanged(Location location) {
			// TODO add sync lock
			setLocation(location);
		}

		@Override
		public void onProviderDisabled(String arg0) {
			// TODO Auto-generated method stub
			Log.d("Location updates disabled", arg0);
			
		}

		@Override
		public void onProviderEnabled(String arg0) {
			// TODO Auto-generated method stub
			Log.d("Location updates enabled", arg0);			
		}

		@Override
		public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
			// TODO Auto-generated method stub
			Log.d("Location status changed", arg0);	
		}
	}
			
	private class WifiReceiver extends BroadcastReceiver {
		
		List<ScanResult> lastWifiList;	
		
		public void onReceive(Context c, Intent intent) {
			
			Log.d("New wifi list", "");
			StringBuilder sb = new StringBuilder();
			lastWifiList = wifiManager.getScanResults();
			Location location = lastLocation;
			double lat,lon,alt;
			if (location != null) {
				lat = location.getLatitude() ;
				lon = location.getLongitude() ; 
				alt = location.getAltitude();
			} 
			else {
				lat = 0.0;
				lon = 0.0;
				alt = 0.0;
			}
			
	        for(int i = 0; i < lastWifiList.size(); i++){
	        	sb.append(new Integer(i+1).toString() + ".");
	        	sb.append((lastWifiList.get(i)).toString());
	        	sb.append("\n\n");
	        	updateDB(lastWifiList.get(i),lat,lon,alt);
	        }
        	
	        mainText.setText(sb);
		}
	}
}